package com.xcgame.oh;

import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;

/**
 * OkHttp
 * <br/>
 * Created by 小灿 on 2016/11/11.
 */

public class OkHttp {

    private static final int CALL_FAILURE = 11;
    private static final int CALL_RESPONSE_SUCCESS = 22;
    private static final int CALL_RESPONSE_FAILURE = 33;
    private static final int CALL_CANCEL = 44;
    private static final int CALL_RESPONSE_PATH = 66;
    private static final int CALL_RESPONSE_PROGRESS = 77;

    public static final String TAG = "OkHttp";
    public static boolean isPrintLog = true;

    private OkHttpClient client;

    public OkHttp() {
        client = new OkHttpClient.Builder().
                connectTimeout(5, TimeUnit.SECONDS).
                readTimeout(15, TimeUnit.SECONDS).
                writeTimeout(15, TimeUnit.SECONDS)
                .build();
    }

    /**
     * @param connectTimeout 连接超时（秒钟）
     */
    public OkHttp(int connectTimeout, int readTimeout, int writeTimeout) {
        client = new OkHttpClient.Builder().connectTimeout(connectTimeout, TimeUnit.SECONDS).readTimeout(readTimeout, TimeUnit.SECONDS).
                writeTimeout(writeTimeout, TimeUnit.SECONDS).build();
    }

    /**
     * get请求（同时能请求很多个）
     *
     * @param context
     * @param url
     * @param callback
     * @return
     */
    public Call get(final Context context, String url, final ResponseCallback callback) {

        callback.setContext(context);
        callback.setUrl(url);

        if (checkNetworkConnectivity(context) != 1 && checkNetworkConnectivity(context) != 2) {
            callback.onStart();
            callback.onFinish();
            callback.isNotOpenNetwork();
            return null;
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                if (context instanceof Activity) {
                    Activity activity = (Activity) context;
                    if (activity.isFinishing()) {
                        return;
                    }
                }
                if (msg.what == CALL_FAILURE) {
                    callback.onFinish();
                    callback.onFailure(0);
                }
                if (msg.what == CALL_RESPONSE_SUCCESS) {
                    String response = (String) msg.obj;
                    callback.onFinish();
                    callback.onSuccess(response);
                }
                if (msg.what == CALL_RESPONSE_FAILURE) {
                    int code = (int) msg.obj;
                    callback.onFinish();
                    callback.onFailure(code);
                }
                if (msg.what == CALL_CANCEL) {
                    callback.onFinish();
                    callback.onCancel();
                }
            }
        };

        Request request = new Request.Builder().url(url).build();
        final Call call = client.newCall(request);

        call.enqueue(new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {

                if (call.isCanceled()) {
                    handler.sendEmptyMessage(CALL_CANCEL);
                } else {
                    handler.sendEmptyMessage(CALL_FAILURE);
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                if (response.isSuccessful()) {
                    String result = response.body().string();
                    Message message = handler.obtainMessage();
                    message.what = CALL_RESPONSE_SUCCESS;
                    message.obj = result;
                    handler.sendMessage(message);
                } else {
                    Message message = handler.obtainMessage();
                    message.what = CALL_RESPONSE_FAILURE;
                    message.obj = response.code();
                    handler.sendMessage(message);
                }
            }

        });

        callback.onStart();
        return call;
    }

    /**
     * post请求 (同时能请求很多个)
     *
     * @param context
     * @param url
     * @param params
     * @param callback
     * @return
     */
    public Call post(final Context context, String url, Map<String, String> params, final ResponseCallback callback) {

        callback.setContext(context);
        callback.setUrl(url);

        if (checkNetworkConnectivity(context) != 1 && checkNetworkConnectivity(context) != 2) {
            callback.onStart();
            callback.onFinish();
            callback.isNotOpenNetwork();
            return null;
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                if (context instanceof Activity) {
                    Activity activity = (Activity) context;
                    if (activity.isFinishing()) {
                        return;
                    }
                }
                if (msg.what == CALL_FAILURE) {
                    callback.onFinish();
                    callback.onFailure(0);
                }
                if (msg.what == CALL_RESPONSE_SUCCESS) {
                    String response = (String) msg.obj;
                    callback.onFinish();
                    callback.onSuccess(response);
                }
                if (msg.what == CALL_RESPONSE_FAILURE) {
                    int code = (int) msg.obj;
                    callback.onFinish();
                    callback.onFailure(code);
                }
                if (msg.what == CALL_CANCEL) {
                    callback.onFinish();
                    callback.onCancel();
                }
            }
        };

        FormBody.Builder builder = new FormBody.Builder();
        if (params != null) {
            for (Map.Entry entry : params.entrySet()) {
                builder.add(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()));
            }
        }

        Request request = new Request.Builder().url(url).post(builder.build()).build();
        final Call call = client.newCall(request);

        call.enqueue(new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {

                if (call.isCanceled()) {
                    handler.sendEmptyMessage(CALL_CANCEL);
                } else {
                    handler.sendEmptyMessage(CALL_FAILURE);
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                if (response.isSuccessful()) {
                    String result = response.body().string();
                    Message message = handler.obtainMessage();
                    message.what = CALL_RESPONSE_SUCCESS;
                    message.obj = result;
                    handler.sendMessage(message);
                } else {
                    Message message = handler.obtainMessage();
                    message.what = CALL_RESPONSE_FAILURE;
                    message.obj = response.code();
                    handler.sendMessage(message);
                }

            }
        });

        callback.onStart();
        return call;
    }


    /**
     * 下载文件
     *
     * @param context
     * @param url
     * @param callback
     */
    public Call downloadFile(final Context context, String url, final DownloadResponseCallback callback) {

        callback.setContext(context);
        callback.setUrl(url);

        if (checkNetworkConnectivity(context) != 1 && checkNetworkConnectivity(context) != 2) {
            callback.onStart();
            callback.onFinish();
            callback.isNotOpenNetwork();
            return null;
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                if (context instanceof Activity) {
                    Activity activity = (Activity) context;
                    if (activity.isFinishing()) {
                        return;
                    }
                }
                if (msg.what == CALL_FAILURE) {
                    callback.onFinish();
                    callback.onFailure(0);
                }
                if (msg.what == CALL_RESPONSE_PROGRESS) {
                    int response = (int) msg.obj;
                    callback.onProgress(response);
                }
                if (msg.what == CALL_RESPONSE_PATH) {
                    String response = (String) msg.obj;
                    callback.onFinish();
                    callback.onSuccess(response);
                }
                if (msg.what == CALL_RESPONSE_FAILURE) {
                    int code = (int) msg.obj;
                    callback.onFinish();
                    callback.onFailure(code);
                }
                if (msg.what == CALL_CANCEL) {
                    callback.onFinish();
                    callback.onCancel();
                }
            }
        };


        Request request = new Request.Builder().url(url).build();
        final Call call = client.newCall(request);

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handler.sendEmptyMessage(CALL_FAILURE);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                long total = response.body().contentLength();
                long sum = 0;

                InputStream is = null;
                FileOutputStream fos = null;
                String dirPath = callback.getTargetDirPath(context);
                File dir = new File(dirPath);
                if (!dir.exists()) {
                    dir.mkdirs();
                }
                File file = new File(dirPath, System.currentTimeMillis() + ".log");
                try {
                    is = response.body().byteStream();
                    fos = new FileOutputStream(file);
                    byte[] buffer = new byte[2048];
                    int readCount;
                    while ((readCount = is.read(buffer)) != -1) {

                        sum += readCount;
                        int progress = (int) (sum * 1.0f / total * 100);

                        Message message = handler.obtainMessage();
                        message.what = CALL_RESPONSE_PROGRESS;
                        message.obj = progress;
                        handler.sendMessage(message);

                        fos.write(buffer, 0, readCount);
                    }
                    fos.flush();

                    Message message = handler.obtainMessage();
                    message.what = CALL_RESPONSE_PATH;
                    message.obj = file.getAbsolutePath();
                    handler.sendMessage(message);

                } catch (IOException e) {
                    if (file.exists()) {
                        file.delete();
                    }
                    handler.sendEmptyMessage(CALL_CANCEL);

                } finally {
                    try {
                        if (is != null)
                            is.close();
                    } catch (IOException e) {
                    }
                    try {
                        if (fos != null)
                            fos.close();
                    } catch (IOException e) {
                    }
                }

                if (!response.isSuccessful()) {
                    Message message = handler.obtainMessage();
                    message.what = CALL_RESPONSE_FAILURE;
                    message.obj = response.code();
                    handler.sendMessage(message);
                }
            }
        });

        callback.onStart();
        return call;
    }

    /**
     * 上传文件
     *
     * @param context
     * @param url
     * @param file
     * @param callback
     * @return
     */
    public Call uploadFile(final Context context, String url, Map<String, String> params, final File file, final UploadResponseCallback callback) {

        callback.setContext(context);
        callback.setUrl(url);

        if (checkNetworkConnectivity(context) != 1 && checkNetworkConnectivity(context) != 2) {
            callback.onStart();
            callback.onFinish();
            callback.isNotOpenNetwork();
            return null;
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                if (context instanceof Activity) {
                    Activity activity = (Activity) context;
                    if (activity.isFinishing()) {
                        return;
                    }
                }
                if (msg.what == CALL_FAILURE) {
                    callback.onFinish();
                    callback.onFailure(0);
                }
                if (msg.what == CALL_RESPONSE_PROGRESS) {
                    int response = (int) msg.obj;
                    callback.onProgress(response);
                }
                if (msg.what == CALL_RESPONSE_SUCCESS) {
                    String response = (String) msg.obj;
                    callback.onFinish();
                    callback.onSuccess(response);
                }
                if (msg.what == CALL_RESPONSE_FAILURE) {
                    int code = (int) msg.obj;
                    callback.onFinish();
                    callback.onFailure(code);
                }
                if (msg.what == CALL_CANCEL) {
                    callback.onFinish();
                    callback.onCancel();
                }
            }
        };

        MultipartBody.Builder builder = new MultipartBody.Builder();
        builder.setType(MultipartBody.FORM);

        if (params != null) {
            for (Map.Entry entry : params.entrySet()) {
                builder.addFormDataPart(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()));
            }
        }

        if (file != null && file.exists()) {
            RequestBody requestBody = new RequestBody() {
                @Override
                public MediaType contentType() {
                    return MultipartBody.FORM;
                }

                @Override
                public long contentLength() {
                    return file.length();
                }

                @Override
                public void writeTo(BufferedSink sink) throws IOException {
                    Source source;
                    try {
                        source = Okio.source(file);
                        Buffer buf = new Buffer();
                        Long remaining = contentLength();
                        for (long readCount; (readCount = source.read(buf, 2048)) != -1; ) {
                            sink.write(buf, readCount);
                            remaining = remaining - readCount;
                            long complete = contentLength() - remaining;
                            int progress = (int) (complete / contentLength() * 100);
                            Message message = handler.obtainMessage();
                            message.what = CALL_RESPONSE_PROGRESS;
                            message.obj = progress;
                            handler.sendMessage(message);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            };
            builder.addFormDataPart("imgData", file.getName(), requestBody);
        }

        Request request = new Request.Builder().url(url).post(builder.build()).build();
        final Call call = client.newCall(request);

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                if (call.isCanceled()) {
                    handler.sendEmptyMessage(CALL_CANCEL);
                } else {
                    handler.sendEmptyMessage(CALL_FAILURE);
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    String result = response.body().string();
                    Message message = handler.obtainMessage();
                    message.what = CALL_RESPONSE_SUCCESS;
                    message.obj = result;
                    handler.sendMessage(message);

                } else {
                    Message message = handler.obtainMessage();
                    message.what = CALL_RESPONSE_FAILURE;
                    message.obj = response.code();
                    handler.sendMessage(message);
                }
            }
        });

        callback.onStart();
        return call;

    }

    /**
     * 上传文件
     *
     * @param context
     * @param url
     * @param file
     * @param callback
     * @return
     */
    public Call uploadFile(final Context context, String url, final File file, final UploadResponseCallback callback) {

        if (file == null || !file.exists()) {
            return null;
        }

        callback.setContext(context);
        callback.setUrl(url);

        if (checkNetworkConnectivity(context) != 1 && checkNetworkConnectivity(context) != 2) {
            callback.onStart();
            callback.onFinish();
            callback.isNotOpenNetwork();
            return null;
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                if (context instanceof Activity) {
                    Activity activity = (Activity) context;
                    if (activity.isFinishing()) {
                        return;
                    }
                }
                if (msg.what == CALL_FAILURE) {
                    callback.onFinish();
                    callback.onFailure(0);
                }
                if (msg.what == CALL_RESPONSE_PROGRESS) {
                    int response = (int) msg.obj;
                    callback.onProgress(response);
                }
                if (msg.what == CALL_RESPONSE_SUCCESS) {
                    String response = (String) msg.obj;
                    callback.onFinish();
                    callback.onSuccess(response);
                }
                if (msg.what == CALL_RESPONSE_FAILURE) {
                    int code = (int) msg.obj;
                    callback.onFinish();
                    callback.onFailure(code);
                }
                if (msg.what == CALL_CANCEL) {
                    callback.onFinish();
                    callback.onCancel();
                }
            }
        };

        MultipartBody.Builder builder = new MultipartBody.Builder();
        builder.setType(MultipartBody.FORM);

        RequestBody requestBody = new RequestBody() {
            @Override
            public MediaType contentType() {
                return MultipartBody.FORM;
            }

            @Override
            public long contentLength() {
                return file.length();
            }

            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                Source source;
                try {
                    source = Okio.source(file);
                    Buffer buf = new Buffer();
                    Long remaining = contentLength();
                    for (long readCount; (readCount = source.read(buf, 2048)) != -1; ) {
                        sink.write(buf, readCount);
                        remaining = remaining - readCount;
                        long complete = contentLength() - remaining;
                        int progress = (int) (complete / contentLength() * 100);
                        Message message = handler.obtainMessage();
                        message.what = CALL_RESPONSE_PROGRESS;
                        message.obj = progress;
                        handler.sendMessage(message);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };

        builder.addFormDataPart("file", file.getName(), requestBody);

        Request request = new Request.Builder().url(url).post(builder.build()).build();
        final Call call = client.newCall(request);

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                if (call.isCanceled()) {
                    handler.sendEmptyMessage(CALL_CANCEL);
                } else {
                    handler.sendEmptyMessage(CALL_FAILURE);
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    String result = response.body().string();
                    Message message = handler.obtainMessage();
                    message.what = CALL_RESPONSE_SUCCESS;
                    message.obj = result;
                    handler.sendMessage(message);

                } else {
                    Message message = handler.obtainMessage();
                    message.what = CALL_RESPONSE_FAILURE;
                    message.obj = response.code();
                    handler.sendMessage(message);
                }
            }
        });

        callback.onStart();
        return call;

    }

    /**
     * 取消所有的网络请求
     */
    public void cancelAll() {
        client.dispatcher().cancelAll();
    }

    public void cancel(Call call) {
        if (call != null) {
            call.cancel();
        }
    }

    /**
     * 检查手机网络连通性
     *
     * @return 0：没打开网络连接
     * <br/>
     * 1：当前为mobile网络
     * <br/>
     * 2：当前为wifi网络
     */
    public int checkNetworkConnectivity(Context context) {

        //获取这个权限需要在manifest中添加"android.permission.ACCESS_NETWORK_STATE"权限
        ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = manager.getActiveNetworkInfo();

        if (networkInfo != null) {
            //2.获取当前网络连接的类型信息
            int networkType = networkInfo.getType();
            if (ConnectivityManager.TYPE_WIFI == networkType) {
                return 2;
                //当前为wifi网络
            } else if (ConnectivityManager.TYPE_MOBILE == networkType) {
                return 1;
                //当前为mobile网络
            }
        }

        return 0;
    }

}
